package app.server.project.main.service.service.task;

import app.server.project.core.constants.TcpCmd;
import app.server.project.core.exception.SysError;
import app.server.project.core.util.AssertUtil;
import app.server.project.core.websocket.WSMgr;
import app.server.project.main.service.bo.event.TaskFinishEvent;
import app.server.project.main.service.db.dao.cfg.RaceCfgDao;
import app.server.project.main.service.db.dao.cfg.TaskCfgDao;
import app.server.project.main.service.db.dao.user.UserTaskDao;
import app.server.project.main.service.dto.recharge.TaskInfoDto;
import app.server.project.main.service.dto.task.TaskReq;
import app.server.project.main.service.service.EnergyService;
import app.server.project.main.service.service.ResService;
import app.server.project.main.service.service.lang.LangService;
import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
@AllArgsConstructor
public class TaskService {


    private final TaskCfgDao taskCfgDao;
    private final UserTaskDao userTaskDao;
    private RaceCfgDao raceCfgDao;
    private LangService langService;
    private EnergyService energyService;
    private ResService resService;
    private ApplicationContext applicationContext;
    private ApplicationEventPublisher applicationEventPublisher;


    public List<TaskInfoDto> getTask(long userId, String lang) {
        var cfgLst = this.taskCfgDao.getAllLst();
        var ret = cfgLst.stream().map(v -> {
            return this.getDto(userId, v.getId(), lang);
        }).collect(Collectors.toList());
        return ret;
    }


    /**
     * 任务完成事件
     *
     * @param event
     */
    @EventListener(TaskFinishEvent.class)
    public void finish(TaskFinishEvent event) {
        var dbList = this.userTaskDao.getAll(event.getUserId());
        var cfg = this.taskCfgDao.getOneByTaskId(event.getTaskId());
        var dbOne = this.userTaskDao.getOne(dbList, event.getTaskId(), event.getUserId());
        if (dbOne.getStatus() == TaskStatusType.UnFinish || dbOne.getStatus() == TaskStatusType.Verify) {
            dbOne.addFinishNum(event.getFinishNum());
        }
        dbOne.setStatus(TaskStatusType.Finish);
        WSMgr.push(event.getUserId(), TcpCmd.Task, this.getDto(event.getUserId(), event.getTaskId(), null));
    }


    private TaskInfoDto getDto(long userId, int taskId, String lang) {
        var dbList = this.userTaskDao.getAll(userId);
        var cfg = this.taskCfgDao.getOneByTaskId(taskId);
        var dbOne = this.userTaskDao.getOne(dbList, taskId, userId);
        var raceCfg = this.raceCfgDao.getOne(cfg.getRaceId());
        if (StrUtil.isNotBlank(lang)) {
            return TaskInfoDto.of(cfg, dbOne);
        }
        return TaskInfoDto.of(cfg, dbOne);
    }


    public void receive(long userId, int taskId) {
        var dbList = this.userTaskDao.getAll(userId);
        var cfg = this.taskCfgDao.getOneByTaskId(taskId);
        var dbOne = this.userTaskDao.getOne(dbList, taskId, userId);
        AssertUtil.isTrue(dbOne.getStatus() == TaskStatusType.Finish, SysError.Task_Receive_Fail);
        //奖励体力
        this.energyService.addEnergy(userId, cfg.getEnergy());
        var raceCfg = this.raceCfgDao.getOne(cfg.getRaceId());
        //奖励代币
        this.resService.addResNum(userId, cfg.getRaceId(), cfg.getRaceVal(), true);
        dbOne.setStatus(TaskStatusType.WithDraw);
        WSMgr.push(userId, TcpCmd.Task, this.getDto(userId, taskId, null));
        //this.applicationEventPublisher.publishEvent(AddRaceValEvent.of(userId, raceCfg, cfg.getRaceVal(), DetailType.Task));
    }

    public void changeVerifyStatus(TaskReq req, long userId) {
        var tasks = this.userTaskDao.getAll(userId);
        var task = this.userTaskDao.getOne(tasks, req.getTaskId(), userId);
        task.setStatus(TaskStatusType.Verify);
        WSMgr.push(userId, TcpCmd.Task, this.getDto(userId, req.getTaskId(), null));
    }

    public void verifyTask(TaskReq req, long userId) {
        var cfg = this.taskCfgDao.getOneByTaskId(req.getTaskId());
        ITaskVerify taskVerify = null;
        try {
            taskVerify = (ITaskVerify) this.applicationContext.getBean(VerifyType.Package_Name + cfg.getVerifyType());
        } catch (Exception e) {
        }
        if (Objects.nonNull(taskVerify)) {
            taskVerify.doLogic(req.getTaskId(), userId);
        } else {
            //没有校验,就直接相信前端
            this.finish(TaskFinishEvent.of(userId, req.getTaskId(), 1));
        }
    }
}
